/* Copyright 2014 Jan Wolter */

#include "stack.h"
#include "found.h"

/* Array of foundation piles used in this game */
FoundStack *foundation;
int foundsize= 0;       /* current size of foundation array */

int (*superfound)(Stack *s, int index1, int len)= NULL;

int found_mayInsert(Stack *dst, Card *card, int len, Stack *src)
{
    if (len > 1) return 0;

    FoundStack *f= foundation + dst->tid;

    if (card->s != f->basesuit) return 0;
    if (dst->n == f->maxsize) return 0;
    if (dst->n == 0)
	return (card->n == f->baserank);
    else
	return (card->n == (topStack(dst)->n + f->buildstep + npip - 1)%npip + 1);
}


void makeFound(int baserank, int basesuit, int buildstep, int maxsize)
{
    /* Make sure we have memory for another foundation pile */
    if (foundsize == 0)
    {
	foundsize= 8;
	foundation= (FoundStack *)malloc(foundsize*sizeof(FoundStack));
    }
    else if (nfound == foundsize)
    {
	foundsize+= 8;
	foundation= (FoundStack *)realloc(foundation,foundsize*sizeof(FoundStack));
    }

    /* Create the foundation pile */
    foundation[nfound].baserank= baserank;
    foundation[nfound].basesuit= basesuit;
    foundation[nfound].buildstep= buildstep;
    foundation[nfound].maxsize= maxsize;

    /* It starts out empty, but we allocate enough memory for it to be full.
     * firstMove and nextMove are NULL since we don't allow cards to move back
     * off of the foundation.
     *
     * If a foundation super handler was defined, we don't need mayInsert and
     * we don't want to be put on the dstlist.
     */
    foundation[nfound].id= newStack(FOUND,nfound,maxsize,
	    superfound ? NULL : found_mayInsert,
	    NULL, NULL, NULL);

    nfound++;
}

void cleanFound()
{
    free(foundation);
    nfound= foundsize= 0;
}

void printFound(FILE *f, Stack *stks)
{
    char label[8];
    for (int k= 0; k < nfound; k++)
    {
	sprintf(label,"F%02d", k+1);
	printStack(f, label, stks+foundation[k].id);
    }
}

int nOff()
{
    int n= 0;
    for (int k= 0; k < nfound; k++)
	n+= stacks[foundation[k].id].n;
    return n;
}

/* Remove cards from all foundations and append them to the given stack,
 * reversing them all.
 */
void gatherFound(Stack *s)
{
    for (int k= 0; k < nfound; k++)
    {
	Stack *fs= stacks+foundation[k].id;
	appendStack(s, fs, 1);
    }
}

/* Superhandlers are shortcut methods for some common foundation configurations
 * To use one, we point the global "superfound" to the function we want to
 * use, and do not put the individual foundation piles in dstlist.
 */

/* Superhandler for foundations with one stack per suit, starting with ace,
 *  building up in suit. Works for multiple suits, so long as the foundation
 *  piles for suit "s" are pile numbers s, s+nsuit, s+2*nsuit, ...
 *
 *  Given a card, returns the index in "stacks" of a foundation stack it
 *  can be moved to. Returns -1 if there is none.
 */
int sf_acebase(Stack *s, int index1, int len)
{
    if (len != 1) return -1;
    Card *c= s->c[index1];
    int fi= foundation[c->s].id;
    for (int d= 0; d < ndeck; d++)
    {
	if (stacks[fi].n == c->n - 1) return fi;
	fi+= nsuit;
    }
    return -1;
}

/* Like sf_acebase(), except foundation piles build from king down two ace */
int sf_kingdown(Stack *s, int index1, int len)
{
    if (len != 1) return -1;
    Card *c= s->c[index1];
    int fi= foundation[c->s].id;
    for (int d= 0; d < ndeck; d++)
    {
	if (stacks[fi].n == 13 - c->n) return fi;
	fi+= nsuit;
    }
    return -1;
}

/* Like sf_acebase(), except foundation piles all have the same basecard
 * as foundation[0].
 */
int sf_constbase(Stack *s, int index1, int len)
{
    if (len != 1) return -1;
    Card *c= s->c[index1];
    int fi= foundation[c->s].id;
    for (int d= 0; d < ndeck; d++)
    {
	if ((c->n - foundation[0].baserank + npip)%npip == stacks[fi].n)
	    return fi;
	fi+= nsuit;
    }
    return -1;
}

/* Can only move a complete sequence to foundation. Foundation piles must be
 * one per suit, in same order as defined for sf_acebase. */
int sf_complete(Stack *src, int index1, int len)
{
    /* Bottom card of stack */
    if (len != npip) return -1;
    Card *c= src->c[index1+len-1];

    /* Find an empty foundation stack to move it into */
    int k= c->s;
    int fi= foundation[k].id;
    for (int d= 0; d < ndeck; d++)
    {
	/* Check that the sequence fits here */
	if (stacks[fi].n == 0 &&
	    c->n == foundation[k].baserank &&
	    checkseq(S_SAMESUIT, -foundation[k].buildstep, foundation[k].baserank,
		src->c+index1, len))
	    return fi;
	fi+= nsuit;
	k+= nsuit;
    }
    return -1;
}
